//
//  TestLayer.m
//  Box2dDemo
//
//  Created by Thi Huynh on 9/6/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "TestLayer.h"
#import "PhysicObject.h"
#import "Bubble.h"
#import "WeaponTrailEffect.h"
#import "StarEffect.h"
#import "TestObject.h"
#import "CutHelper.h"

@interface PhysicsLayer (PrivateMethods)
- (CCSprite*) addRandomSpriteAt:(CGPoint)pos;
- (void)explode;

@end

@implementation TestLayer
#pragma mark - init section

- (id)init
{
    self = [super init];
    if(self)
    {
        //TODO: create game component, property init here
        //[self createWorldWithPlane:440 pos:ccp(20, 100)];
        [self createWorldwithFixScreen];
        [self setIsTouchEnabled:YES];
        [self createComponent];
        [self scheduleUpdate];
        [self schedule:@selector(createSprite) interval:1];
    }
    return self;
}

-(void)createSprite
{
    [self addRanDomSpriteWithNum:10];
    [self unschedule:_cmd];
}

#pragma mark - create section
- (void)createComponent
{
    _physicObjects = [[NSMutableArray alloc]init];
    //create effect
    splurt = [CCParticleSystemQuad particleWithFile:@"explosion.plist"];
    [splurt setVisible:NO];
    [self addChild:splurt z:100];
    ring = [CCParticleSystemQuad particleWithFile:@"ring.plist"];
    [ring setVisible:NO];
    [self addChild:ring z:100];
}

- (void)createSpriteAt:(CGPoint)pos
{
    CCSprite* _sprite = [CCSprite spriteWithFile:IMG_OBJECT_BOMB];
    [_sprite setPosition:pos];
    [self addChild:_sprite z:90 tag:EnumObjCircleTag];
    //create body
    [self createBodyWithSprite:_sprite joint:NO];
}

- (void)createBodyWithSprite:(CCSprite*)sprite joint:(BOOL)joint
{
    b2BodyDef _bodyDef;
    _bodyDef.type = b2_dynamicBody;
    _bodyDef.position.Set(sprite.position.x/PTM_RATIO, sprite.position.y/PTM_RATIO);
	_bodyDef.userData = sprite;
	b2Body *body = world->CreateBody(&_bodyDef);
    //create fixture
    b2PolygonShape bompShape;
    bompShape.SetAsBox(sprite.boundingBox.size.width/(PTM_RATIO*2), sprite.boundingBox.size.width/(PTM_RATIO*2)) ;
    
	// Define the dynamic body fixture.
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &bompShape;	
	fixtureDef.density = 0.5f;
	fixtureDef.friction = 0.3f;
    fixtureDef.restitution = 0.001f;
	body->CreateFixture(&fixtureDef);

    //get last body
    if(_physicObjects.count > 0)
    {
        b2Body* _lastBody = (b2Body*)((NSValue*)([_physicObjects objectAtIndex:(_physicObjects.count-1)])).pointerValue;
        if(joint)
        {
            [_physicObjects addObject:[NSValue valueWithPointer:body]];
            [self createJoint:EnumWeldJoint :_lastBody bodyB:body];
            NSLog(@"Physic objectc count[%d]",_physicObjects.count);
        }
    //add to array
    }
}

- (void)addRanDomSpriteWithNum:(int)num
{
    for(int i = 0;i < num ;i++)
    {
        //make random pos
        float x = arc4random() % 480;
        float y = arc4random() % 320;
        TestObject* _sprite = [[TestObject alloc]initPolygonWith:world fileName:IMG_OBJECT_WATERMELON andPos:ccp(x, y)];
        [self addChild:_sprite];
        [_sprite setTag:EnumObjCircleTag];
        //create body
        //[self createBodyWithSprite:_sprite joint:YES];
    }
}

#pragma mark - create joints
- (void)createJoint:(enum EnumJointType)type :(b2Body*)bodyA bodyB:(b2Body*)bodyB;
{
    switch (type) 
    {
        case EnumDistanceJoint:
            [self createDistanceJoint:bodyA bodyB:bodyB];
            break;
        case EnumGearJoint:
            [self createGearJoint:bodyA bodyB:bodyB];
            break;
        case EnumFrictionJoint:
            [self createFrictionJoint:bodyA bodyB:bodyB];
            break;
        case EnumMouseJoint:
            [self createMouseJoint:bodyA bodyB:bodyB];
            break;
        case EnumPrismaticJoint:
            [self createPrismaticJoint:bodyA bodyB:bodyB];
            break;
        case EnumPulleyJoint:
            [self createPulleyJoint:bodyA bodyB:bodyB];
            break;
        case EnumRevoluteJoint:
            [self createRevoluteJoint:bodyA bodyB:bodyB];
            break;
        case EnumWeldJoint:
            [self createWeildJoint:bodyA bodyB:bodyB];
            break;
        case EnumWheelJoint:
            [self createWheelJoint:bodyA bodyB:bodyB];
            break;
            
        default:
            break;
    }
}

- (void)createWheelJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2WheelJointDef jointDef;
    jointDef.Initialize(bodyA, bodyB, b2Vec2((bodyA->GetWorldCenter().x + bodyB->GetWorldCenter().x)/2, (bodyA->GetWorldCenter().y + bodyB->GetWorldCenter().y)/2), b2Vec2(0, 1));
    bodyA->GetWorld()->CreateJoint(&jointDef);
}
- (void)createMouseJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2MouseJointDef jointDef;
    bodyA->GetWorld()->CreateJoint(&jointDef);

}
- (void)createRevoluteJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2RevoluteJointDef jointDef;
    jointDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter());
    bodyA->GetWorld()->CreateJoint(&jointDef);
}
- (void)createDistanceJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2DistanceJointDef jointDef;
    jointDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter(), bodyB->GetWorldCenter());
    bodyA->GetWorld()->CreateJoint(&jointDef);
}
- (void)createPrismaticJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2PrismaticJointDef jointDef;
    
    b2Vec2 worldAxis(1.0f, 0.0f);
    
    jointDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter(), worldAxis);
    
    jointDef.lowerTranslation = -5.0f;
    
    jointDef.upperTranslation = 2.5f;
    
    jointDef.enableLimit = true;
    
    jointDef.maxMotorForce = 1.0f;
    
    jointDef.motorSpeed = 0.0f;
    
    jointDef.enableMotor = true;
}
- (void)createWeildJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2WeldJointDef jointDef;
    jointDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter());   
    bodyA->GetWorld()->CreateJoint(&jointDef);

}
- (void)createPulleyJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2PulleyJointDef jointDef;
    bodyA->GetWorld()->CreateJoint(&jointDef);

}
- (void)createFrictionJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2FrictionJointDef joinDef;
    joinDef.Initialize(bodyA, bodyB, bodyA->GetWorldCenter());
    bodyA->GetWorld()->CreateJoint(&joinDef);
}
- (void)createGearJoint:(b2Body*)bodyA bodyB:(b2Body*)bodyB
{
    b2GearJointDef joinDef;
    bodyA->GetWorld()->CreateJoint(&joinDef);
}

#pragma mark - touch section
- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL: location];
    WeaponTrailEffect* _effect = [[WeaponTrailEffect alloc]init];
    [_effect setPosition:location];
    
    _pointA = ccp(location.x, 320);
    _pointB   = ccp(location.x, 0);
    _pointA1 = ccp(0, location.y);
    _pointB1   = ccp(480, location.y);
    
    // set effect
    splurt.position = location;
    [splurt setVisible:YES];
    [splurt resetSystem];
    
    ring.position = location;
    [ring setVisible:YES];
    [ring resetSystem];
    
    cuts = [[CutHelper getInstance] getArrayOfCuts:location radius:200 cuts:6];
    /*for(int i = 0; i < cuts.size(); i++)
    {
        CGPoint pointA = cuts[i*2+0];
        CGPoint pointB = cuts[i*2+1];
        [[CutHelper getInstance] splitAllBodyWith:world layer:self from:pointA to:pointB];
    }*/
    //[[CutHelper getInstance] splitAllBodyWith:world layer:self from:_pointA to:_pointB];
    //[[CutHelper getInstance] splitAllBodyWith:world layer:self from:_pointA1 to:_pointB1];
    [[CutHelper getInstance] splitBodyWith:world layer:self atPoint:location cuts:20];
    
}
- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL: location];
}

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInView: [touch view]];
    location = [[CCDirector sharedDirector] convertToGL: location];
    //explode with force in radius
     world->ClearForces();
    //[[BodyActionHelper sharedInstance] cutSpritesWithTag:EnumObjCircleTag fromPoint:location inRadius:50 cuts:10 fromWorld:world];
    [ExplodeHelper createExplodeWith:world atPoint:location radius:300 maxForce:100 suction:NO];
}
#pragma mark - action


#pragma mark - update section
-(void) update:(ccTime)delta
{
    // The number of iterations influence the accuracy of the physics simulation. With higher values the
	// body's velocity and position are more accurately tracked but at the cost of speed.
	// Usually for games only 1 position iteration is necessary to achieve good results.
	float timeStep = 0.03f;
	int32 velocityIterations = 8;
	int32 positionIterations = 1;
	world->Step(timeStep, velocityIterations, positionIterations);
	// for each body, get its assigned sprite and update the sprite's position
	for (b2Body* body = world->GetBodyList(); body != nil; body = body->GetNext())
	{
		CCSprite* sprite = (__bridge CCSprite*)body->GetUserData();
		if (sprite != NULL)
		{
			// update the sprite's position to where their physics bodies are
			sprite.position = [MathHelper toPixels:body->GetPosition()];
			float angle = body->GetAngle();
			sprite.rotation = CC_RADIANS_TO_DEGREES(angle) * -1;
		}
	}
}

#pragma mark - draw section
- (void)draw
{
    //ccDrawLine(_pointA, _pointB);
    //ccDrawLine(_pointA1, _pointB1);
    if(cuts.size()>0)
    {
        for(int i = 0; i < cuts.size(); i++)
        {
            CGPoint pointA = cuts[i*2+0];
            CGPoint PointB = cuts[i*2+1];
           // ccDrawLine(pointA, PointB);
        }
    }
    
}
#pragma mark - dealloc section
- (void)dealloc
{
    if(_physicObjects)
    {
        [_physicObjects removeAllObjects];
        [_physicObjects release];
        _physicObjects = nil;
    }
    [super dealloc];
}

@end
